package com.comut.crud.jms;

import com.comut.crud.util.Util;
import com.comut.lib.connection.MongoDBConnectionManager;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
 * Issue: IFL-1566. Gets info for vehicles
 *
 * @author Vitor Borrego
 */
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destination",
            propertyValue = "queue/VehicleInfoQueue"),
    @ActivationConfigProperty(propertyName = "acknowledgeMode",
            propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType",
            propertyValue = "javax.jms.Queue")
})
public class VehicleInfoMDB implements MessageListener {

    private Connection jmsConnection;
    private Session jmsSession;
    private MessageProducer producer;
    private DB mongoDatabase;
    private MongoDBConnectionManager mongoDB;
    private Mongo mongoConnection;
    private DBCollection mobileInfo;

    /**
     * Issue: IFL-1566
     */
    @PostConstruct
    private void postConstruct() {
        try {
            this.checkMongoDBConnection();
            this.connectJMS();

        } catch (Exception ex) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Issue: IFL-1566
     */
    @PreDestroy
    private void preDestroy() {
        try {
            this.mongoDB.freeConnection(this.mongoConnection, this.mongoDatabase);
            this.jmsSession.close();
            this.jmsConnection.close();
        } catch (Exception ex) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Issue: IFL-1566
     *
     * @param msg
     */
    public void onMessage(Message msg) {
        if (msg instanceof TextMessage) {
            this.checkMongoDBConnection();
            TextMessage textMessage = (TextMessage) msg;

            try {
                int vehicleId = textMessage.getIntProperty("vehicleId");
                String taskId = textMessage.getStringProperty("taskId");
                // db.hist.find({vid:2750},{"_id":1,"gsp":1,"hdg":1,"loc.lat":1 ,"loc.lon":1 , "tmp.tp1":1,"tmp.tp2":1,"tmp.tp3":1,"tmp.tp4":1,"tmx":1 }).sort({tmx:-1}).limit(1).pretty()

                BasicDBObject fieldsHist = new BasicDBObject();
                fieldsHist.put("_id", 1);
                fieldsHist.put("pos.gsp", 1); //int
                fieldsHist.put("pos.hdg", 1); //int
                fieldsHist.put("pos.loc.lat", 1); //double
                fieldsHist.put("pos.loc.lon", 1); //double 
                fieldsHist.put("pos.tmx", 1); //date
                fieldsHist.put("tmp.tp1", 1); //double
                fieldsHist.put("tmp.tp2", 1); //double
                fieldsHist.put("tmp.tp3", 1); //double
                fieldsHist.put("tmp.tp4", 1); //double

                BasicDBObject queryMongo = new BasicDBObject();
                queryMongo.put("mid", vehicleId);
                DBObject result = this.mobileInfo.findOne(queryMongo, fieldsHist);

                if (result != null) {
//                    ObjectId idDocument = (ObjectId) result.get("_id");
                    //Logger.getLogger(this.getClass().getName()).log(Level.INFO, String.format("%s", this.showString(idDocument)));
                    DBObject pos = (DBObject) result.get("pos");
                    Integer gsp = Integer.parseInt(pos.get("gsp").toString());
                    Integer hdg = Integer.parseInt(pos.get("hdg").toString());
                    //Long postmx = Long.parseLong(pos.get("tmx").toString());
                    DBObject loc = (DBObject) pos.get("loc");
                    Double lat = Double.parseDouble(loc.get("lat").toString());
                    Double lon = Double.parseDouble(loc.get("lon").toString());
                    String fractal = Util.getFractal(lat, lon);

                    DBObject tmp = (DBObject) result.get("tmp");
                    Integer tp1 = null;
                    Integer tp2 = null;
                    Integer tp3 = null;
                    Integer tp4 = null;
                    boolean hasTemperature = false;

                    if (tmp != null) {
                        tp1 = getInteger(tmp.get("tp1"));
                        tp2 = getInteger(tmp.get("tp2"));
                        tp3 = getInteger(tmp.get("tp3"));
                        tp4 = getInteger(tmp.get("tp4"));
                        hasTemperature = true;
                    }

                    TextMessage replyMessage = jmsSession.createTextMessage("Reply");
                    replyMessage.setStringProperty("taskId", taskId);
                    replyMessage.setIntProperty("vehicleId", vehicleId);
                    replyMessage.setIntProperty("gsp", gsp);
                    replyMessage.setIntProperty("hdg", hdg);
                    replyMessage.setDoubleProperty("lat", lat);
                    replyMessage.setDoubleProperty("lon", lon);
                    replyMessage.setStringProperty("fractal", fractal);
                    replyMessage.setBooleanProperty("hasTemperature", hasTemperature);

                    if (hasTemperature) {
                        if (tp1 != null) {
                            replyMessage.setIntProperty("tp1", tp1);
                        }

                        if (tp2 != null) {
                            replyMessage.setIntProperty("tp2", tp2);
                        }

                        if (tp3 != null) {
                            replyMessage.setIntProperty("tp3", tp3);
                        }

                        if (tp4 != null) {
                            replyMessage.setIntProperty("tp4", tp4);
                        }
                    }

                    this.producer.send(replyMessage, DeliveryMode.NON_PERSISTENT, 9, 10000);
                }

            } catch (Exception ex) {
                Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Issue: IFL-1566
     *
     * @param obj
     * @return
     */
    private Integer getInteger(Object obj) {
        Integer ret = null;
        // temperature types on dev.mobile_info tmp.tp1 .... tp4 are mixed ... NoSQL beauty !!!!

        if (obj instanceof Integer) {
            ret = (Integer) obj;
        }

        if (obj instanceof Double) {
            Double d = (Double) obj;

            if (d != null) {
                ret = new Integer(d.intValue());
            }
        }

        return ret;
    }

    /**
     * Issue: IFL-1566
     *
     * @throws UnknownHostException
     */
    private void connectMongoDB() throws UnknownHostException {
        this.mongoDB = MongoDBConnectionManager.instanceFromSystemProperties();
        this.mongoConnection = mongoDB.getConnection();
        this.mongoDatabase = mongoDB.getDB(this.mongoConnection);
        this.mobileInfo = this.mongoDatabase.getCollection("mobile_info");
    }

    /**
     * Issue: IFL-1566 Checks the mongoDB connection
     */
    private void checkMongoDBConnection() {
        if (this.mongoDB == null || this.mongoDB.isAlive(this.mongoConnection) == false) {
            try {
                this.connectMongoDB();
            } catch (UnknownHostException ex) {
                Logger.getLogger(VehicleInfoMDB.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Issue: IFL-1566
     *
     * @throws NamingException
     * @throws JMSException
     */
    private void connectJMS() throws NamingException, JMSException {
        InitialContext ic = new InitialContext();
        ConnectionFactory cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
        Queue vehicleInfoReplyQueue = (Queue) ic.lookup("/queue/VehicleInfoReplyQueue");
        this.jmsConnection = (javax.jms.Connection) cf.createConnection();
        this.jmsSession = (Session) jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        this.producer = jmsSession.createProducer(vehicleInfoReplyQueue);
        jmsConnection.start();
    }
}
